package com.suredy.app.project.model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

import com.suredy.app.project.constants.ProjectStatus;
import com.suredy.core.model.BaseModel;
import com.suredy.security.entity.UnitEntity;
import com.suredy.security.entity.UserEntity;

/**
 * 项目信息
 * 
 * @author VIVID.G
 * @since 2015-7-29
 * @version v0.1
 */
@Entity
@Table(name = "tb_project", indexes = {@Index(unique = true, columnList = "no"), @Index(columnList = "name")})
public class Project extends BaseModel {

	private static final long serialVersionUID = 1L;

	/* 项目编号 */
	@Column(length = 100, nullable = false)
	private String no;

	/* 项目类型 */
	@Column(length = 50, nullable = false)
	private String type;

	/* 项目名称 */
	@Column(length = 200, nullable = false)
	private String name;

	/* 客户单位 */
	@Column(length = 200)
	private String customerCompany;

	/* 客户部门 */
	@Column(length = 200)
	private String customerUnit;

	/* 联系人 */
	@Column(length = 30)
	private String customerPeople;

	/* 联系电话 */
	@Column(length = 20)
	private String customerPhone;

	/* 项目状态 */
	@Column(length = 100, nullable = false)
	@Enumerated(EnumType.STRING)
	private ProjectStatus status;

	/* 项目起获方式 */
	@Column(length = 100)
	private String obtainType;

	/* 是否签订合同 */
	@Column(nullable = false, columnDefinition = "int default 0")
	private Boolean contracted;

	/* 合同签订状况描述 */
	@Column(length = 500)
	private String contractDesc;

	/* 项目管理部门 */
	@ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
	@JoinColumn(name = "manage_dep_id")
	private UnitEntity manageDep;

	/* 是否已经开具发票 */
	@Column(nullable = false, columnDefinition = "int default 0")
	private Boolean invoiced;

	/* 开具发票日期 */
	private Date invoiceDate;

	/* 发票开具描述 */
	@Column(length = 500)
	private String invoiceDesc;

	/* 项目描述 */
	@Column(length = 500)
	private String des;

	/* 创建时间 */
	@Column(nullable = false)
	private Date createTime;

	/* 起始日期 */
	private Date start;

	/* 结束日期 */
	private Date end;

	/* 成本支出 */
	@OneToMany(mappedBy = "project", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@Fetch(FetchMode.SUBSELECT)
	@OrderBy("payTime")
	private List<ProjectCost> costs;

	/* 成员列表 */
	@OneToMany(mappedBy = "project", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@Fetch(FetchMode.SUBSELECT)
	private List<ProjectMember> members;

	/* 合同列表 */
	@OneToMany(mappedBy = "project", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@Fetch(FetchMode.SUBSELECT)
	@OrderBy("type, no")
	private List<Contract> contracts;

	public String getNo() {
		return no;
	}

	public void setNo(String no) {
		this.no = no;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getCustomerCompany() {
		return customerCompany;
	}

	public void setCustomerCompany(String customerCompany) {
		this.customerCompany = customerCompany;
	}

	public String getCustomerUnit() {
		return customerUnit;
	}

	public void setCustomerUnit(String customerUnit) {
		this.customerUnit = customerUnit;
	}

	public String getCustomerPeople() {
		return customerPeople;
	}

	public void setCustomerPeople(String customerPeople) {
		this.customerPeople = customerPeople;
	}

	public String getCustomerPhone() {
		return customerPhone;
	}

	public void setCustomerPhone(String customerPhone) {
		this.customerPhone = customerPhone;
	}

	public ProjectStatus getStatus() {
		return status;
	}

	public void setStatus(ProjectStatus status) {
		this.status = status;
	}

	public String getObtainType() {
		return obtainType;
	}

	public void setObtainType(String obtainType) {
		this.obtainType = obtainType;
	}

	public Boolean getContracted() {
		return contracted;
	}

	public void setContracted(Boolean contracted) {
		this.contracted = contracted;
	}

	public String getContractDesc() {
		return contractDesc;
	}

	public void setContractDesc(String contractDesc) {
		this.contractDesc = contractDesc;
	}

	public UnitEntity getManageDep() {
		return manageDep;
	}

	public void setManageDep(UnitEntity manageDep) {
		this.manageDep = manageDep;
	}

	public Boolean getInvoiced() {
		return invoiced;
	}

	public void setInvoiced(Boolean invoiced) {
		this.invoiced = invoiced;
	}

	public Date getInvoiceDate() {
		return invoiceDate;
	}

	public void setInvoiceDate(Date invoiceDate) {
		this.invoiceDate = invoiceDate;
	}

	public String getInvoiceDesc() {
		return invoiceDesc;
	}

	public void setInvoiceDesc(String invoiceDesc) {
		this.invoiceDesc = invoiceDesc;
	}

	public String getDes() {
		return des;
	}

	public void setDes(String des) {
		this.des = des;
	}

	public Date getCreateTime() {
		return createTime;
	}

	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}

	public Date getStart() {
		return start;
	}

	public void setStart(Date start) {
		this.start = start;
	}

	public Date getEnd() {
		return end;
	}

	public void setEnd(Date end) {
		this.end = end;
	}

	public List<ProjectCost> getCosts() {
		return costs;
	}

	public void setCosts(List<ProjectCost> costs) {
		this.costs = costs;
	}

	public List<ProjectMember> getMembers() {
		return members;
	}

	public void setMembers(List<ProjectMember> members) {
		this.members = members;
	}

	public List<Contract> getContracts() {
		return contracts;
	}

	public void setContracts(List<Contract> contracts) {
		this.contracts = contracts;
	}

	// 以下是业务方法

	@Transient
	public UserEntity getManager() {
		List<ProjectMember> members = this.getMembers();

		if (members == null || members.isEmpty())
			return null;

		for (ProjectMember m : members) {
			if (m.getManager())
				return m.getUser();
		}

		return null;
	}

	@Transient
	public List<UserEntity> getMembersWithoutManager() {
		List<ProjectMember> members = this.getMembers();

		if (members == null || members.isEmpty())
			return null;

		List<UserEntity> ret = new ArrayList<UserEntity>();

		for (ProjectMember m : members) {
			if (!m.getManager())
				ret.add(m.getUser());
		}

		Collections.sort(ret, new Comparator<UserEntity>() {

			public int compare(UserEntity o1, UserEntity o2) {
				String n1 = o1.getName();
				String n2 = o2.getName();

				return n1.compareTo(n2);
			}
		});

		return ret.isEmpty() ? null : ret;
	}

	@Transient
	public Contract getMainContract() {
		List<Contract> contracts = this.getContracts();

		if (contracts == null || contracts.isEmpty())
			return null;

		for (Contract c : contracts) {
			if (c.getMainContract())
				return c;
		}

		return null;
	}

	@Transient
	public List<Contract> getChildrenContract() {
		List<Contract> contracts = this.getContracts();

		if (contracts == null || contracts.isEmpty())
			return null;

		List<Contract> children = new ArrayList<Contract>();

		for (Iterator<Contract> it = contracts.iterator(); it.hasNext();) {
			Contract c = it.next();

			if (!c.getMainContract())
				children.add(c);
		}

		return children.isEmpty() ? null : children;
	}

	@Transient
	public float getCostCount() {
		if (this.getCosts() == null)
			return 0F;

		float count = 0F;

		for (ProjectCost cost : this.getCosts()) {
			if (cost.getPay() != null)
				count += cost.getPay();
		}

		return count;
	}

	@Transient
	public float getProfit() {
		// TODO:
		Contract mainContract = this.getMainContract();

		if (mainContract == null)
			return 0;

		if (mainContract.getPayPrice() == null || mainContract.getPayPrice() == 0)
			return 0;

		float payPrice = mainContract.getPayPrice();
		float costCount = this.getCostCount();

		return payPrice - costCount;
	}

	@Transient
	public float getProfitRatio() {
		Contract mainContract = this.getMainContract();

		if (mainContract == null)
			return 0;

		if (mainContract.getPayPrice() == null || mainContract.getPayPrice() == 0)
			return 0;

		float payPrice = mainContract.getPayPrice();

		return this.getProfit() / payPrice;
	}

}
